home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 9 / Example 9.3 / unit.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-15  |  8.2 KB  |  335 lines

  1. #include "unit.h"
  2.  
  3. std::vector<SKINNEDMESH*> unitMeshes;
  4.  
  5. void LoadUnitResources(IDirect3DDevice9* Device)
  6. {
  7.     std::vector<std::string> fnames;
  8.  
  9.     fnames.push_back("units/drone.x");
  10.     fnames.push_back("units/soldier.x");
  11.     fnames.push_back("units/magician.x");
  12.  
  13.     for(int i=0;i<fnames.size();i++)
  14.     {
  15.         SKINNEDMESH *newMesh = new SKINNEDMESH();
  16.         newMesh->Load((char*)fnames[i].c_str(), Device);
  17.         unitMeshes.push_back(newMesh);
  18.     }
  19. }
  20.  
  21. void UnloadUnitResources()
  22. {
  23.     for(int i=0;i<unitMeshes.size();i++)
  24.         if(unitMeshes[i] != NULL)
  25.             delete unitMeshes[i];
  26.  
  27.     unitMeshes.clear();
  28. }
  29.  
  30. //////////////////////////////////////////////////////////////////////////////////
  31. //                                UNIT                                            //
  32. //////////////////////////////////////////////////////////////////////////////////
  33.  
  34. UNIT::UNIT(int _type, int _team, INTPOINT mp, TERRAIN *_terrain, IDirect3DDevice9* Dev) : MAPOBJECT()
  35. {
  36.     m_type = _type;
  37.     m_team = _team;
  38.     m_mappos = mp;
  39.     m_pTerrain = _terrain;
  40.     m_pDevice = Dev;
  41.     m_mapsize.Set(1, 1);
  42.     m_time = m_pauseTime = 0.0f;
  43.     m_animation = m_activeWP = 0;
  44.     m_rotation = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  45.     m_scale = D3DXVECTOR3(0.2f, 0.2f, 0.2f);
  46.     m_isBuilding = m_moving = false;
  47.     m_movePrc = 0.0f;
  48.  
  49.     if(m_pTerrain != NULL)
  50.     {
  51.         m_position = m_pTerrain->GetWorldPos(m_mappos);
  52.         MAPTILE *tile = m_pTerrain->GetTile(m_mappos);
  53.         if(tile != NULL)tile->m_pMapObject = this;
  54.     }
  55.     else m_position = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  56.  
  57.     if(m_type == 0)        //Farmer
  58.     {
  59.         m_hp = m_hpMax = 100;
  60.         m_range = 1;
  61.         m_damage = 5;
  62.         m_sightRadius = 7;
  63.         m_speed = 1.0f;
  64.         m_name = "Farmer";
  65.     }    
  66.     else if(m_type == 1)        //Soldier
  67.     {
  68.         m_hp = m_hpMax = 180;
  69.         m_range = 1;
  70.         m_damage = 12;
  71.         m_sightRadius = 8;
  72.         m_speed = 0.8f;
  73.         m_name = "Soldier";
  74.     }    
  75.     else if(m_type == 2)        //Magician
  76.     {
  77.         m_hp = m_hpMax = 100;
  78.         m_range = 5;
  79.         m_damage = 8;
  80.         m_sightRadius = 10;
  81.         m_speed = 1.1f;
  82.         m_name = "Magician";
  83.     }    
  84.  
  85.     m_pAnimControl = unitMeshes[m_type]->GetAnimationControl();
  86.     if(m_pAnimControl != NULL)
  87.         m_pAnimControl->ResetTime();
  88.  
  89.     SetAnimation("Still");
  90. }
  91.  
  92. UNIT::~UNIT()
  93. {
  94.     if(m_pTerrain != NULL)
  95.     {
  96.         MAPTILE *tile = m_pTerrain->GetTile(m_mappos);
  97.         if(tile != NULL)tile->m_pMapObject = NULL;
  98.     }
  99. }
  100.  
  101. void UNIT::Render()
  102. {
  103.     if(m_type < unitMeshes.size() && unitMeshes[m_type] != NULL)
  104.     {
  105.         SetAnimation(m_animation);
  106.  
  107.         unitMeshes[m_type]->SetPose(GetWorldMatrix(), m_pAnimControl, m_time);
  108.         unitMeshes[m_type]->Render(NULL);
  109.         m_time = 0.0f;
  110.     }
  111. }
  112.  
  113. void UNIT::Update(float deltaTime)
  114. {
  115.     //Pause the units...
  116.     if(m_pauseTime > 0.0f)
  117.     {
  118.         m_pauseTime -= deltaTime;
  119.         return;
  120.     }
  121.  
  122.     //update unit animation time
  123.     m_time += deltaTime * 0.8f * m_speed;
  124.  
  125.     //if the unit is moving...
  126.     if(m_moving)
  127.     {
  128.         if(m_movePrc < 1.0f)m_movePrc += deltaTime * m_speed;
  129.         if(m_movePrc > 1.0f)m_movePrc = 1.0f;
  130.         
  131.         //Goal reached
  132.         if(m_movePrc == 1.0f)
  133.         {
  134.             if(m_activeWP + 1 >= m_path.size())
  135.             {
  136.                 m_moving = false;
  137.                 SetAnimation("Still");
  138.                 if(m_mappos != m_finalGoal)Goto(m_finalGoal, false, true);
  139.             }
  140.             else if(!CheckCollision(m_path[m_activeWP + 1])) //Next Waypoint
  141.             {            
  142.                 m_activeWP++;
  143.                 SetAnimation("Run");
  144.                 MoveUnit(m_path[m_activeWP]);
  145.             }
  146.         }
  147.  
  148.         //Interpolate position between lastWP and nextWP
  149.         m_position = m_lastWP * (1.0f - m_movePrc) + m_nextWP * m_movePrc;
  150.     }
  151. }
  152.  
  153. bool UNIT::CheckCollision(INTPOINT mp)
  154. {
  155.     MAPTILE *tile = m_pTerrain->GetTile(mp);
  156.     if(tile == NULL)return false;
  157.  
  158.     if(tile->m_pMapObject != NULL && tile->m_pMapObject != this)    //Collision with another unit
  159.     {
  160.         UNIT *otherUnit = (UNIT*)tile->m_pMapObject;
  161.  
  162.         //The other unit is moving
  163.         if(otherUnit->m_moving && otherUnit->m_pauseTime <= 0.0f && m_speed <= otherUnit->m_speed)
  164.         {
  165.             //Pause the unit and wait for the other one to move 
  166.             Pause((100 + rand()%200) / 1000.0f);
  167.             m_path.clear();
  168.         }
  169.         else    //Recalculate path
  170.         {
  171.             //Find next unoccupied walkable tile
  172.             INTPOINT tempGoal = m_mappos;
  173.             for(int i=m_activeWP+1;i<m_path.size();i++)
  174.             {
  175.                 MAPTILE *tile = m_pTerrain->GetTile(m_path[i]);
  176.                 if(tile != NULL)
  177.                     if(tile->m_walkable && tile->m_pMapObject == NULL)
  178.                     {
  179.                         tempGoal = m_path[i];
  180.                         break;
  181.                     }
  182.             }
  183.  
  184.             //No available tile found 
  185.             if(tempGoal == m_mappos)
  186.             {
  187.                 //Move to tile closest to the original goal
  188.                 INTPOINT newGoal = m_pTerrain->GetClosestFreeTile(m_finalGoal, m_mappos);
  189.  
  190.                 if(newGoal == m_mappos || m_mappos.Distance(m_finalGoal) < 2.0f)
  191.                 {
  192.                     m_moving = false;
  193.                     SetAnimation("Still");
  194.                 }
  195.                 else Goto(newGoal, false, true);
  196.             }
  197.             else 
  198.             {
  199.                 //Move to tempGoal to avoid unit, then continue to finalGoal
  200.                 Goto(tempGoal, true, false); 
  201.             }
  202.         }
  203.  
  204.         return true;    //A Collision happened
  205.     }
  206.     
  207.     return false;        //No Collision
  208. }
  209.  
  210. void UNIT::Goto(INTPOINT mp, bool considerUnits, bool _finalGoal)
  211. {
  212.     if(m_pTerrain == NULL)return;
  213.     if(_finalGoal)m_finalGoal = mp;
  214.     
  215.     //Clear old path
  216.     m_path.clear();
  217.     m_activeWP = 0;
  218.  
  219.     if(m_moving)        //If unit is currently moving
  220.     {
  221.         //Finish the active waypoint 
  222.         m_path.push_back(m_mappos);
  223.         std::vector<INTPOINT> tmpPath = m_pTerrain->GetPath(m_mappos, mp, considerUnits);
  224.  
  225.         //add new path
  226.         for(int i=0;i<tmpPath.size();i++)
  227.             m_path.push_back(tmpPath[i]);
  228.     }
  229.     else        //Create new path from scratch...
  230.     {
  231.         m_path = m_pTerrain->GetPath(m_mappos, mp, considerUnits);
  232.         
  233.         if(m_path.size() > 0)        //if a path was found
  234.         {
  235.             m_moving = true;
  236.  
  237.             //Check that the next tile is free
  238.             if(!CheckCollision(m_path[m_activeWP]))
  239.             {
  240.                 MoveUnit(m_path[m_activeWP]);
  241.                 SetAnimation("Run");                
  242.             }
  243.         }
  244.     }
  245. }
  246.  
  247. void UNIT::MoveUnit(INTPOINT to)
  248. {
  249.     m_lastWP = m_pTerrain->GetWorldPos(m_mappos);
  250.     m_rotation = GetDirection(m_mappos, to);
  251.  
  252.     //Clear old MAPTILE unit pointer
  253.     MAPTILE *tile = m_pTerrain->GetTile(m_mappos);
  254.     if(tile != NULL)tile->m_pMapObject = NULL;
  255.  
  256.     m_mappos = to;    //New mappos
  257.     m_movePrc = 0.0f;
  258.     m_nextWP = m_pTerrain->GetWorldPos(m_mappos);
  259.  
  260.     //Set new MAPTILE unit pointer
  261.     tile = m_pTerrain->GetTile(m_mappos);
  262.     if(tile != NULL)tile->m_pMapObject = this;
  263. }
  264.  
  265. void UNIT::Pause(float time)
  266. {
  267.     SetAnimation("Still");
  268.     m_pauseTime = time;
  269. }
  270.  
  271. BBOX UNIT::GetBoundingBox()
  272. {
  273.     if(m_type == 0)        //Farmer
  274.         return BBOX(m_position + D3DXVECTOR3(0.3f, 1.0f, 0.3f), m_position - D3DXVECTOR3(0.3f, 0.0f, 0.3f));
  275.     else if(m_type == 1)    //Soldier
  276.         return BBOX(m_position + D3DXVECTOR3(0.35f, 1.2f, 0.35f), m_position - D3DXVECTOR3(0.35f, 0.0f, 0.35f));
  277.     else if(m_type == 2)    //Magician
  278.         return BBOX(m_position + D3DXVECTOR3(0.3f, 1.1f, 0.3f), m_position - D3DXVECTOR3(0.3f, 0.0f, 0.3f));
  279. }
  280.  
  281. D3DXMATRIX UNIT::GetWorldMatrix()
  282. {
  283.     D3DXMATRIX s, p, r;
  284.     D3DXMatrixTranslation(&p, m_position.x, m_position.y, m_position.z);
  285.     D3DXMatrixRotationYawPitchRoll(&r, m_rotation.y, m_rotation.x, m_rotation.z);
  286.     D3DXMatrixScaling(&s, m_scale.y, m_scale.x, m_scale.z);
  287.     return s * r * p;
  288. }
  289.  
  290. D3DXVECTOR3 UNIT::GetDirection(INTPOINT p1, INTPOINT p2)
  291. {
  292.     int dx = p2.x - p1.x, dy = p2.y - p1.y;
  293.     
  294.     if(dx < 0 && dy > 0)    return D3DXVECTOR3(0.0f, D3DX_PI/4,        0.0f); 
  295.     if(dx == 0 && dy > 0)    return D3DXVECTOR3(0.0f, 0.0f,            0.0f);
  296.     if(dx > 0 && dy > 0)    return D3DXVECTOR3(0.0f, -D3DX_PI/4,    0.0f); 
  297.     if(dx > 0 && dy == 0)    return D3DXVECTOR3(0.0f, -D3DX_PI/2,    0.0f);
  298.     if(dx > 0 && dy < 0)    return D3DXVECTOR3(0.0f, (-D3DX_PI/4)*3,0.0f); 
  299.     if(dx == 0 && dy < 0)    return D3DXVECTOR3(0.0f, D3DX_PI,        0.0f);
  300.     if(dx < 0 && dy < 0)    return D3DXVECTOR3(0.0f, (D3DX_PI/4)*3,    0.0f); 
  301.     if(dx < 0 && dy == 0)    return D3DXVECTOR3(0.0f, D3DX_PI/2,        0.0f);
  302.  
  303.     return m_rotation;
  304. }
  305.  
  306. void UNIT::SetAnimation(char name[])
  307. {
  308.     ID3DXAnimationSet *anim = NULL;
  309.     m_animation = 0;
  310.  
  311.     for(int i=0;i<m_pAnimControl->GetMaxNumAnimationSets();i++)
  312.     {
  313.         anim = NULL;
  314.         m_pAnimControl->GetAnimationSet(i, &anim);
  315.  
  316.         if(anim != NULL)
  317.         {
  318.             if(strcmp(name, anim->GetName()) == 0)
  319.             {
  320.                 m_pAnimControl->ResetTime();
  321.                 m_pAnimControl->SetTrackAnimationSet(0, anim);
  322.                 m_animation = i;
  323.             }
  324.             anim->Release();
  325.         }
  326.     }
  327. }
  328.  
  329. void UNIT::SetAnimation(int index)
  330. {
  331.     ID3DXAnimationSet *anim = NULL;
  332.     m_pAnimControl->GetAnimationSet(index, &anim);
  333.     if(anim != NULL)m_pAnimControl->SetTrackAnimationSet(0, anim);
  334.     anim->Release();
  335. }